package com.iretailer.report.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iretailer.report.dto.PageResult;
import com.iretailer.report.dto.QueryOption;
import com.iretailer.report.mapper.UserMapper;
import com.iretailer.report.model.*;
import com.iretailer.report.util.GetId;
import com.iretailer.report.util.MD5Util;
import com.iretailer.report.util.StringUtil;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Auther: xjw
 * @Date: 2019/1/22 10:45
 * @Description:
 */
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
    public final static String companyUserSplit = "_#_";

    private Logger log = LoggerFactory.getLogger(UserService.class);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserMallService userMallService;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private PageWidgetsUserService pageWidgetsUserService;

    public List<User> selectAllOrderByName() {
        return userMapper.selectList(new QueryWrapper<User>().lambda().orderByAsc(User::getName));
    }


    /**
     * 保存一个实体，null属性也会保存
     */
    public int insert(User user) {
        return userMapper.insert(user);
    }

    public List<User> selectUserByUserCode(String usrCode) {
        return userMapper.selectList(new QueryWrapper<User>().lambda().eq(User::getUserCode, usrCode));
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public User selectUser(String userCompany, String userCode, String userPass) {
        List<User> findUsers = selectUserByUserCode(userCode);
        if (findUsers.size() > 0) {
            String userPassMd5 = MD5Util.getMd5(userPass);
            List<User> results = new ArrayList<>();
            for (User user : findUsers) {
                if (user.getUserPwd().equals(userPassMd5)) {
                    userMapper.updateTryTimes(user.getId(), 0);
                    results.add(user);
                    break;
                } else {
                    int tryTimes = user.getTryTimes() + 1;
                    userMapper.updateTryTimes(user.getId(), tryTimes);
                    if (tryTimes >= 20) {
                        userMapper.updateLock(user.getId(), 1, LocalDateTime.now());
                    }
                }
            }
            if (results.size() > 0) {
                if ("false".equals(userCompany)) {
                    if (results.size() == 1) {
                        return results.get(0);
                    } else {
                        return null;
                    }
                } else {
                    for (User user : results) {
                        if (user.getCompanyId().equals("-")) {
                            return user;
                        } else {
                            Companies companies = companyService.getOne(new QueryWrapper<Companies>().lambda().eq(Companies::getName, userCompany));
                            if (companies != null) {
                                if (companies.getId().equals(user.getCompanyId())) {
                                    return user;
                                }
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    public User login(String userCode, String userPass) throws Exception {
        String[] userCodes = userCode.split(companyUserSplit);
        User user = selectUser(userCodes[0], userCodes[1], userPass);
        if (user != null) {
            boolean update = updateUserLockMessage(user);
            if (update) {
                return user;
            }
            return null;
        } else {
            throw new UnknownAccountException("User name or password error!");
        }

    }

    private boolean updateUserLockMessage(User user) throws Exception {
        if (user.getIsLock() != null && user.getIsLock() == 1) {
            if (user.getLockTime() != null) {
                LocalDateTime curTime = LocalDateTime.now();
                int lockMinute = 3;
                long time = Duration.between(curTime, user.getLockTime()).toMinutes();
                if (time >= lockMinute) {
                    userMapper.updateLock(user.getId(), 0, LocalDateTime.now());
                    return true;
                }
            }
            throw new LockedAccountException("The user has been locked");
        } else if (user.getLockTime() != null) {
            userMapper.updateLock(user.getId(), 0, LocalDateTime.now());
            return true;
        }
        return false;
    }

    /**
     * 根据权限展示 所有用户
     * 排序的是user的基础属性
     */
    public PageResult<UserRole> grid(String parentId, String companyName, String userCode, String name, String roleName, QueryOption queryOption) {
        Page page = new Page<UserRole>(1, Long.MAX_VALUE);
        QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("1", 1);
        if (parentId != null) {
            List<String> childs = getTreeId(parentId);
            childs.add(parentId);
            queryWrapper.in("parentId", childs);
//            queryWrapper.eq("parentId", parentId);
        }
//        if (companyName != null) {
        queryWrapper.like(companyName != null, "companyName", companyName);
//        }
        if (userCode != null) {
            queryWrapper.like("userCode", userCode);
        }
        if (name != null) {
            queryWrapper.like("name", name);
        }
        if (roleName != null) {
            queryWrapper.like("roleName", roleName);
        }
        queryOption.judge(page, queryWrapper);
        queryWrapper.orderByAsc("CompanyName");
        userMapper.selectPageUserRoleMallIds(page, queryWrapper);
        return new PageResult<>(page.getTotal(), page.getRecords());

    }

    /**
     * 添加和修改
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public boolean saveOrUpdate(User user, String parentId, String userName) {
        user.setUpdateUser(userName);
        user.setUpdateTime(LocalDateTime.now());
        if (StringUtil.notEmpty(user.getUserPwd())) {
            user.setUserPwd(MD5Util.getMd5(user.getUserPwd()));
        }
        if (StringUtil.notEmpty(user.getId())) {
            userMapper.updateById(user);
//            userMapper.update(user, new QueryWrapper<User>().lambda().eq(User::getId, user.getId()));
        } else {
            user.setId(GetId.UUID());
            user.setParentId(parentId);
            user.setLockTime(LocalDateTime.now());
            user.setCreateUser(userName);
            user.setCreateTime(LocalDateTime.now());
            userMapper.insert(user);
            //把父id的首页赋值给它
            List<PageWidgetsUser> pwus = pageWidgetsUserService.list(new QueryWrapper<PageWidgetsUser>().lambda().eq(PageWidgetsUser::getUserId, parentId));
            if (pwus != null && pwus.size() > 0) {
                pwus.forEach(it -> {
                    it.setId(null);
                    it.setUserId(user.getId());
                });
                pageWidgetsUserService.replacePageWidgets_users(pwus);
            }
        }
        return true;
    }

    /**
     * 重置密码
     *
     * @param id
     * @param password
     * @param userName
     * @return
     */
    public boolean resetPassword(String id, String password, String userName) {
        if (StringUtil.notEmpty(password)) {
            userMapper.updatePwd(id, MD5Util.getMd5(password), userName, LocalDateTime.now());
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据 userId 更新 lock
     * lock 默认为0 锁住为1
     */
    public boolean updateLock(String userId, int isLock, LocalDateTime lockTIme) {
        int result = userMapper.updateLock(userId, isLock, lockTIme);
        if (result > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public boolean deleteByIds(List<String> ids) {
        userMallService.remove(new QueryWrapper<UserMall>().lambda().in(UserMall::getUserId, ids));
        userMapper.deleteBatchIds(ids);
        pageWidgetsUserService.remove(new QueryWrapper<PageWidgetsUser>().lambda().in(PageWidgetsUser::getUserId, ids));
        return true;
    }


    /**
     * 根据 parentId 查出所有的 子id
     */
    public List<String> getTreeId(String parentId) {
        List<User> allUser = selectAllOrderByName();
        List<User> users = convertTree(allUser, parentId);
        List<String> result = convertTreeIds(users, new HashSet<String>());
        return result;
    }

    public List<User> getAllParent(List<User> users, User user, List<User> parents) {
        users.forEach(it -> {
            if (it.getId() != null && it.getId().equals(user.getParentId())) {
                parents.add(it);
                getAllParent(users, it, parents);
            }
        });
        return parents;
    }


    public List<User> convertTree(List<User> users, String parentId) {
        List<User> result = new ArrayList<>();
        users.forEach(it -> {
            if (it.getParentId() != null && it.getParentId().equals(parentId)) {
                it.setChildren(convertTree(users, it.getId()));
                result.add(it);
            }
        });
        return result;
    }

    public List<String> convertTreeIds(List<User> users, Set<String> result) {
        users.forEach(it -> {
            result.add(it.getId());
            if (it.getChildren() != null) {
                convertTreeIds(it.getChildren(), result);
            }
        });
        return new ArrayList<>(result);
    }

    public List<UserRole> selectUserRole(Wrapper queryWrapper) {
        return userMapper.selectUserRole(queryWrapper);
    }
}

